# -*- coding:utf-8 -*-
import re

import psycopg2
import redis
from celery import Task
from pymongo import MongoClient
#import conf
import conf

class InitConnectionTask(Task):
    abstract = True
    _mdb = None
    _rdb = {}
    _prdb = {}
    _ardb = {}
    _rrdb = {}
    _pgdb = {}

    @property
    def mdb(self):
        if InitConnectionTask._mdb is None:
            _mc = MongoClient(conf.MONGO_URI)
            InitConnectionTask._mdb = _mc['boluome']
        return InitConnectionTask._mdb

    @property
    def mdb_fetch(self):
        if InitConnectionTask._mdb is None:
            _mc = MongoClient(conf.MONGO_FETCH_URI)
            InitConnectionTask._mdb = _mc['boluome']
        return InitConnectionTask._mdb

    def rdb(self, db=0):
        if InitConnectionTask._rdb.get(db) is None:
            InitConnectionTask._rdb[db] = redis.StrictRedis(host=conf.REDIS_HOST,
                                                            port=conf.REDIS_PORT,
                                                            db=db,
                                                            encoding='utf-8',
                                                            decode_responses=True)
        return self._rdb.get(db)

    def prdb(self, db=0):
        if InitConnectionTask._prdb.get(db) is None:
            InitConnectionTask._prdb[db] = redis.StrictRedis(host=conf.PAYMENT_REDIS_HOST,
                                                             port=conf.REDIS_PORT,
                                                             db=db,
                                                             charset="utf-8",
                                                             decode_responses=True)
        return self._prdb.get(db)

    def ardb(self, db=0):
        if InitConnectionTask._ardb.get(db) is None:
            InitConnectionTask._ardb[db] = redis.StrictRedis(host=conf.ACTIVITY_REDIS_HOST,
                                                             port=conf.REDIS_PORT,
                                                             db=db,
                                                             encoding='utf-8',
                                                             decode_responses=True)
        return self._ardb.get(db)

    def rrdb(self, db=0):
        if InitConnectionTask._rrdb.get(db) is None:
            InitConnectionTask._rrdb[db] = redis.StrictRedis(host=conf.RRDB_HOST,
                                                             port=conf.RRDB_PORT,
                                                             db=db,
                                                             encoding='utf-8',
                                                             decode_responses=True)
        return InitConnectionTask._rrdb.get(db)

    def pgdb(self, db='account'):
        if InitConnectionTask._pgdb.get(db) is None:
            InitConnectionTask._pgdb[db] = psycopg2.connect(conf.PG_DSN.format(db))
        return InitConnectionTask._pgdb.get(db)


def insert_sql_parse(sql):
    pattern = re.compile("\(.+?\)")
    r = re.findall(pattern, sql)
    r[0] = r[0].replace('(', '')
    r[0] = r[0].replace(')', '')
    r[0] = r[0].replace(' ', '')
    keys = r[0].split(',')
    assert len(keys) == len(r[1].split(','))
    return keys


def pg_insert(sql, data, conn):
    """
    封装PostgreSql语句之 INSERT INTO
    Args:
        sql(str):
        data(list):[{},{}]
    Returns:
        out: list of tuples
    """
    assert isinstance(sql, str)
    assert isinstance(data, list)
    assert ";" in sql
    sql = sql.replace('?', '%s')
    keys = insert_sql_parse(sql)
    # conn.commit()
    # conn.rollback()
    with conn.cursor() as curs:
        sql_pg = ""
        for item in data:
            value = [item.get(k) for k in keys]
            sql_pg += curs.mogrify(sql, value).decode()
        curs.execute(sql_pg)
        conn.commit()
    return


def update_sql_parse(sql):
    sql_list = sql.split(' ')
    sql_list = [v for v in sql_list if '%s' in v]
    sql_clean = ''.join(sql_list)
    sql_clean = sql_clean.replace(';', '')
    sql_clean = sql_clean.replace('=%s', ',')
    keys = [v for v in sql_clean.split(',') if v]
    assert len(keys) > 1
    return keys


def pg_update(sql, data, conn):
    """
    封装PostgreSql语句之 UPDATE
    Args:
        sql(str):
        data(list):[{},{}]
    Returns:
        out: list of tuples
    """
    assert isinstance(sql, str)
    assert isinstance(data, list)
    assert ";" in sql
    sql = sql.replace('?', '%s')
    keys = update_sql_parse(sql)
    # conn.commit()
    # conn.rollback()
    with conn.cursor() as curs:
        sql_pg = ""
        for item in data:
            value = [item.get(k) for k in keys]
            sql_pg += curs.mogrify(sql, value).decode()
        curs.execute(sql_pg)
        conn.commit()
    return


def pg_select(sql, conn, field=None):
    """
    封装PostgreSql语句之 SELECT
    Args:
        sql(str):
    Returns:
        out: list of dict
    datas=pg_select('SELECT key FROM boluome_settlement')
    """
    assert isinstance(sql, str)
    assert ";" in sql
    conn.rollback()
    with conn.cursor() as curs:
        curs.execute(sql)
        keys = curs.description
        data_all = curs.fetchall()
        conn.commit()
    data = []
    for item in data_all:
        data.append({v[0]: item[k] for k, v in enumerate(keys)})
    return data if not field else (data, [v.name for v in keys])